From: tsteven4 <13596209+tsteven4@users.noreply.github.com> Date: Mon, 18 Nov 2024 23:37:34 +0000 (-0700) Subject: Refactor GUI map preview (#1385) X-Git-Tag: archive/raspbian/1.10.0+ds-2+rpi1~1^2~12^2^2~5 X-Git-Url: https://dgit.raspbian.org/%22http://www.example.com/cgi/%22/%22http:/www.example.com/cgi/%22?a=commitdiff_plain;h=186ed56223f23ac8de3545a4c9d56193e93ec640;p=gpsbabel.git Refactor GUI map preview (#1385) * refactor map preview "Show Only This ..." will pan to the selected waypoint or frame the selected track or route. "Show All ..." will recenter the map and reset the bounds. --- diff --git a/gui/gmapdlg.cc b/gui/gmapdlg.cc index 2a7d570b8..ee17d8da5 100644 --- a/gui/gmapdlg.cc +++ b/gui/gmapdlg.cc @@ -22,20 +22,20 @@ //------------------------------------------------------------------------ #include "gmapdlg.h" -#include // for QAbstractButton #include // for QAbstractItemView #include // for QDateTime, operator<, operator> +#include // for QDebug #include // for QFrame #include // for QHBoxLayout #include // for QHeaderView #include // for QItemSelectionModel +#include // for QList #include // for QMenu -#include // for QPushButton +#include // for QModelIndexList #include // for QStandardItemModel #include // for QTreeView -#include // for QVariant #include // for CheckState, ContextMenuPolicy -#include // for QForeachContainer, qMakeForeachContainer, foreach +#include // for qDebug #include "appname.h" // for appName #include "gpx.h" // for GpxWaypoint, GpxTrack, GpxRoute, Gpx, GpxItem, GpxTrackPoint, GpxTrackSegment #include "latlng.h" // for LatLn @@ -101,8 +101,8 @@ void GMapDialog::appendTrackInfo(QStandardItem* it, const GpxTrack& trk) QDateTime stopTime; bool first = true; int count = 0; - foreach (const GpxTrackSegment& seg, trk.getTrackSegments()) { - foreach (const GpxTrackPoint& pt, seg.getTrackPoints()) { + for (const GpxTrackSegment& seg : trk.getTrackSegments()) { + for (const GpxTrackPoint& pt : seg.getTrackPoints()) { count++; QDateTime t = pt.getDateTime(); if (!t.isValid()) { @@ -141,11 +141,10 @@ void GMapDialog::appendRouteInfo(QStandardItem* it, const GpxRoute& rte) } //------------------------------------------------------------------------ -GMapDialog::GMapDialog(QWidget* parent, const QString& gpxFileName, QPlainTextEdit* te): QDialog(parent) +GMapDialog::GMapDialog(QWidget* parent, const Gpx& mapData, QPlainTextEdit* te): QDialog(parent), gpx_(mapData) { ui_.setupUi(this); this->setWindowTitle(QString(appName) + " " + QString("Google Maps")); - gpx_.read(gpxFileName); mapWidget_ = new Map(this, gpx_, te); auto* lay = new QHBoxLayout(ui_.frame); @@ -153,61 +152,57 @@ GMapDialog::GMapDialog(QWidget* parent, const QString& gpxFileName, QPlainTextEd lay->addWidget(mapWidget_); model_ = new QStandardItemModel(this); - menuIndex_ = -1; // Actually set for real in showContextMenu(). wptItem_ = new StandardItem(tr("Waypoints")); wptItem_->setCheckable(true); wptItem_->setCheckState(Qt::Checked); model_->appendRow(wptItem_); - for (int i=0; iappendRow(it); it->setCheckable(true); it->setCheckState(Qt::Checked); - it->setData(QVariant::fromValue((void*)&wpt)); appendWaypointInfo(it, wpt); - wptList_ << it; } trkItem_ = new StandardItem(tr("Tracks")); trkItem_->setCheckable(true); trkItem_->setCheckState(Qt::Checked); model_->appendRow(trkItem_); - for (int i=0; iappendRow(it); it->setCheckable(true); it->setCheckState(Qt::Checked); - it->setData(QVariant::fromValue((void*)&trk)); appendTrackInfo(it, trk); - trkList_ << it; } rteItem_ = new StandardItem(tr("Routes")); rteItem_->setCheckable(true); rteItem_->setCheckState(Qt::Checked); model_->appendRow(rteItem_); - for (int i=0; iappendRow(it); it->setCheckable(true); it->setCheckState(Qt::Checked); - it->setData(QVariant::fromValue((void*)&rte)); appendRouteInfo(it, rte); - rteList_ << it; } ui_.treeView->header()->hide(); ui_.treeView->setModel(model_); ui_.treeView->setExpandsOnDoubleClick(false); connect(model_, &QStandardItemModel::itemChanged, - this, &GMapDialog::itemChangedX); - connect(mapWidget_, &Map::waypointClicked, this, &GMapDialog::waypointClickedX); - connect(mapWidget_, &Map::routeClicked, this, &GMapDialog::routeClickedX); - connect(mapWidget_, &Map::trackClicked, this, &GMapDialog::trackClickedX); + this, &GMapDialog::itemChangedX); + connect(mapWidget_, &Map::waypointClicked, this, [this](int i)->void { + itemClickedX(wptItem_->child(i)); + }); + connect(mapWidget_, &Map::routeClicked, this, [this](int i)->void { + itemClickedX(rteItem_->child(i)); + }); + connect(mapWidget_, &Map::trackClicked, this, [this](int i)->void { + itemClickedX(trkItem_->child(i)); + }); connect(ui_.treeView, &QAbstractItemView::doubleClicked, this, &GMapDialog::treeDoubleClicked); connect(ui_.treeView->selectionModel(), &QItemSelectionModel::selectionChanged, @@ -218,136 +213,93 @@ GMapDialog::GMapDialog(QWidget* parent, const QString& gpxFileName, QPlainTextEd this, &GMapDialog::showContextMenu); } -//------------------------------------------------------------------------- -void GMapDialog::itemChangedX(QStandardItem* it) -{ - bool show = (it->checkState() == Qt::Checked); - if (it == trkItem_) { - if (show) { - mapWidget_->showTracks(gpx_.getTracks()); - } else { - mapWidget_->hideAllTracks(); - } - } - - else if (it == wptItem_) { - if (show) { - mapWidget_->showWaypoints(gpx_.getWaypoints()); - } else { - mapWidget_->hideAllWaypoints(); - } - } - - else if (it == rteItem_) { - if (show) { - mapWidget_->showRoutes(gpx_.getRoutes()); +//------------------------------------------------------------------------ +void GMapDialog::trace(const QString& label, const QStandardItem* it) +{ + if constexpr(debug_) { + QDebug qdb(QtDebugMsg); + qdb.nospace().noquote() << label + ": "; + qdb.quote(); + if (it == nullptr) { + qdb << "null item"; } else { - mapWidget_->hideAllRoutes(); - } - } - - else { - // Individual items, find the right one. - GpxItem* git = static_cast(it->data().value()); - if (git != nullptr) { - git->setVisible(show); - for (int i=0; isetWaypointVisibility(i, show); - } - } - for (int i=0; isetTrackVisibility(i, show); - } - } - for (int i=0; isetRouteVisibility(i, show); - } + QStandardItem* parent = it->parent(); + if (parent == nullptr) { + qdb << "parent: none"; + } else { + qdb << "parent: " << parent->text(); } + qdb << " item: " << it->text() << " (row: " << it->row() << ")"; } } } - -//------------------------------------------------------------------------- -int GMapDialog::waypointIndex(QStandardItem* it) + +//------------------------------------------------------------------------ +void GMapDialog::showHideChild(const QStandardItem* child) { - for (int j=0; jparent(); + bool showTop = (top->checkState() == Qt::Checked); + bool show = showTop && (child->checkState() == Qt::Checked); + int row = child->row(); + if (top == wptItem_) { + mapWidget_->setWaypointVisibility(row, show); + } else if (top == trkItem_) { + mapWidget_->setTrackVisibility(row, show); + } else if (top == rteItem_) { + mapWidget_->setRouteVisibility(row, show); } - return -1; } -//------------------------------------------------------------------------- -int GMapDialog::trackIndex(QStandardItem* it) +//------------------------------------------------------------------------ +void GMapDialog::showHideChildren(const QStandardItem* top) { - for (int j=0; jrowCount(); ++row) { + const QStandardItem* child = top->child(row); + showHideChild(child); } - return -1; } //------------------------------------------------------------------------- -int GMapDialog::routeIndex(QStandardItem* it) +void GMapDialog::itemChangedX(QStandardItem* it) { - for (int j=0; jparent(); + if ((parent == wptItem_) || (parent == trkItem_) || (parent == rteItem_)) { + showHideChild(it); } } - return -1; } //------------------------------------------------------------------------- void GMapDialog::treeDoubleClicked(const QModelIndex& idx) { QStandardItem* it = model_->itemFromIndex(idx); - int i = waypointIndex(it); - if (i >= 0) { + trace("treeDoubleClicked", it); + QStandardItem* parent = it->parent(); + int row = it->row(); + if (parent == wptItem_) { + parent->setCheckState(Qt::Checked); it->setCheckState(Qt::Checked); - gpx_.getWaypoints()[i].setVisible(true); - mapWidget_->panTo(gpx_.getWaypoints()[i].getLocation()); - mapWidget_->setWaypointVisibility(i, true); - return; - } - i = trackIndex(it); - if (i >= 0) { - mapWidget_->frameTrack(i); + mapWidget_->panTo(gpx_.getWaypoints().at(row).getLocation()); + } else if (parent == trkItem_) { + parent->setCheckState(Qt::Checked); it->setCheckState(Qt::Checked); - gpx_.getTracks()[i].setVisible(true); - mapWidget_->setTrackVisibility(i, true); - return; - } - i = routeIndex(it); - if (i >= 0) { - mapWidget_->frameRoute(i); + mapWidget_->frameTrack(row); + } else if (parent == rteItem_) { + parent->setCheckState(Qt::Checked); it->setCheckState(Qt::Checked); - gpx_.getRoutes()[i].setVisible(true); - mapWidget_->setRouteVisibility(i, true); - return; + mapWidget_->frameRoute(row); } } //------------------------------------------------------------------------- -void GMapDialog::waypointClickedX(int i) -{ - if (i>=0 && i < wptList_.size()) { - QStandardItem* it = wptList_[i]; - QModelIndex idx = model_->indexFromItem(it); - ui_.treeView->scrollTo(idx, QAbstractItemView::PositionAtCenter); - ui_.treeView->selectionModel()->select(idx, QItemSelectionModel::ClearAndSelect); - } -} -//------------------------------------------------------------------------- -void GMapDialog::trackClickedX(int i) +void GMapDialog::itemClickedX(const QStandardItem* it) { - if (i>=0 && i indexFromItem(it); ui_.treeView->scrollTo(idx, QAbstractItemView::PositionAtCenter); ui_.treeView->selectionModel()->select(idx, QItemSelectionModel::ClearAndSelect); @@ -355,221 +307,139 @@ void GMapDialog::trackClickedX(int i) } //------------------------------------------------------------------------- -void GMapDialog::routeClickedX(int i) +void GMapDialog::selectionChangedX(const QItemSelection& sel, const QItemSelection& desel) { - if (i>=0 && i indexFromItem(it); - ui_.treeView->scrollTo(idx, QAbstractItemView::PositionAtCenter); - ui_.treeView->selectionModel()->select(idx, QItemSelectionModel::ClearAndSelect); + if constexpr(debug_) { + qDebug() << "selectionChangedX"; } -} - -//------------------------------------------------------------------------- -void GMapDialog::selectionChangedX(const QItemSelection& sel, const QItemSelection& desel) -{ - int k=0; - foreach (QStandardItem* w, wptList_) { - QModelIndex idx = model_->indexFromItem(w); - if (desel.contains(idx)) { - mapWidget_->setWaypointColorBlue(k); + for (const QModelIndexList idxs = desel.indexes(); const auto& idx : idxs) { + const QStandardItem* it = model_->itemFromIndex(idx); + const QStandardItem* parent = it->parent(); + if (parent == wptItem_) { + int row = it->row(); + mapWidget_->setWaypointColorBlue(row); } - if (sel.contains(idx)) { - mapWidget_->setWaypointColorRed(k); + } + for (const QModelIndexList idxs = sel.indexes(); const auto& idx : idxs) { + const QStandardItem* it = model_->itemFromIndex(idx); + const QStandardItem* parent = it->parent(); + if (parent == wptItem_) { + int row = it->row(); + mapWidget_->setWaypointColorRed(row); } - k++; } } //------------------------------------------------------------------------ -void GMapDialog::expandCollapseAll(const QList& li, - QStandardItem* top, bool exp) +void GMapDialog::expandCollapseAll(QStandardItem* top, bool exp) { ui_.treeView->setExpanded(model_->indexFromItem(top), exp); - foreach (QStandardItem* it, li) { - QModelIndex idx = model_->indexFromItem(it); - ui_.treeView->setExpanded(idx, exp); + for (int row = 0; row < top->rowCount(); ++row) { + const QStandardItem* child = top->child(row); + ui_.treeView->setExpanded(model_->indexFromItem(child), exp); } } //------------------------------------------------------------------------ -void GMapDialog::expandAllWaypoints() -{ - expandCollapseAll(wptList_, wptItem_, true); -} -//------------------------------------------------------------------------ -void GMapDialog::expandAllTracks() -{ - expandCollapseAll(trkList_, trkItem_, true); -} -//------------------------------------------------------------------------ -void GMapDialog::expandAllRoutes() -{ - expandCollapseAll(rteList_, rteItem_, true); -} - -//------------------------------------------------------------------------ -void GMapDialog::collapseAllWaypoints() -{ - expandCollapseAll(wptList_, wptItem_,false); -} -//------------------------------------------------------------------------ -void GMapDialog::collapseAllTracks() -{ - expandCollapseAll(trkList_, trkItem_,false); -} -//------------------------------------------------------------------------ -void GMapDialog::collapseAllRoutes() -{ - expandCollapseAll(rteList_, rteItem_,false); -} - -//------------------------------------------------------------------------ -void GMapDialog::checkUncheckAll(const QList& li, - QStandardItem* top, bool ck) +void GMapDialog::showHideAll(QStandardItem* top, bool ck) { - top->setCheckState(ck ? Qt::Checked: Qt::Unchecked); - foreach (QStandardItem* it, li) { - it->setCheckState(ck ? Qt::Checked: Qt::Unchecked); + trace("showHideAll", top); + if (ck) { + mapWidget_->resetBounds(); } -} -//------------------------------------------------------------------------ -void GMapDialog::showAllWaypoints() -{ - foreach (GpxWaypoint wpt, gpx_.getWaypoints()) { - wpt.setVisible(true); - } - checkUncheckAll(wptList_, wptItem_, true); - mapWidget_->showWaypoints(gpx_.getWaypoints()); -} -//------------------------------------------------------------------------ -void GMapDialog::showAllTracks() -{ - foreach (GpxTrack trk, gpx_.getTracks()) { - trk.setVisible(true); - } - checkUncheckAll(trkList_, trkItem_, true); - mapWidget_->showTracks(gpx_.getTracks()); -} - -//------------------------------------------------------------------------ -void GMapDialog::showAllRoutes() -{ - foreach (GpxRoute rte, gpx_.getRoutes()) { - rte.setVisible(true); + top->setCheckState(ck ? Qt::Checked: Qt::Unchecked); + for (int row = 0; row < top->rowCount(); ++row) { + QStandardItem* child = top->child(row); + child->setCheckState(ck ? Qt::Checked: Qt::Unchecked); } - checkUncheckAll(rteList_, rteItem_, true); - mapWidget_->showRoutes(gpx_.getRoutes()); } //------------------------------------------------------------------------ -void GMapDialog::hideAllWaypoints() +void GMapDialog::showOnlyThis(QStandardItem* top, int menuRow) { - foreach (GpxWaypoint wpt, gpx_.getWaypoints()) { - wpt.setVisible(false); + trace("showOnlyThis", top->child(menuRow)); + if (top == wptItem_) { + mapWidget_->panTo(gpx_.getWaypoints().at(menuRow).getLocation()); + } else if (top == trkItem_) { + mapWidget_->frameTrack(menuRow); + } else if (top = rteItem_) { + mapWidget_->frameRoute(menuRow); } - checkUncheckAll(wptList_, wptItem_, false); - mapWidget_->showWaypoints(gpx_.getWaypoints()); -} -//------------------------------------------------------------------------ -void GMapDialog::hideAllTracks() -{ - foreach (GpxTrack trk, gpx_.getTracks()) { - trk.setVisible(false); - } - checkUncheckAll(trkList_, trkItem_, false); - mapWidget_->showTracks(gpx_.getTracks()); - -} -//------------------------------------------------------------------------ -void GMapDialog::hideAllRoutes() -{ - foreach (GpxRoute rte, gpx_.getRoutes()) { - rte.setVisible(false); + for (int row = 0; row < top->rowCount(); ++row) { + QStandardItem* child = top->child(row); + child->setCheckState(row == menuRow? Qt::Checked: Qt::Unchecked); } - checkUncheckAll(rteList_, rteItem_, false); - mapWidget_->showRoutes(gpx_.getRoutes()); - + top->setCheckState(Qt::Checked); } -//------------------------------------------------------------------------ -void GMapDialog::showOnlyThisWaypoint() +void GMapDialog::showTopContextMenu(const QStringList& text, QStandardItem* top, const QPoint& pt) { - QList & wlist = gpx_.getWaypoints(); - for (int i=0; isetCheckState(i==menuIndex_? Qt::Checked: Qt::Unchecked); - } - wptItem_->setCheckState(Qt::Checked); - mapWidget_->showWaypoints(gpx_.getWaypoints()); + QMenu menu(this); + menu.addAction(text.at(0), this, [this, &top]()->void { + showHideAll(top, true); + }); + menu.addAction(text.at(1), this, [this, &top]()->void { + showHideAll(top, false); + }); + menu.addAction(text.at(2), this, [this, &top]()->void { + expandCollapseAll(top, true); + }); + menu.addAction(text.at(3), this, [this, &top]()->void { + expandCollapseAll(top, false); + }); + menu.exec(ui_.treeView->mapToGlobal(pt)); } -//------------------------------------------------------------------------ -void GMapDialog::showOnlyThisTrack() -{ - QList & tlist = gpx_.getTracks(); - for (int i=0; isetCheckState(i==menuIndex_? Qt::Checked: Qt::Unchecked); - } - trkItem_->setCheckState(Qt::Checked); - mapWidget_->showTracks(gpx_.getTracks()); -} -//------------------------------------------------------------------------ -void GMapDialog::showOnlyThisRoute() +void GMapDialog::showChildContextMenu(const QString& text, const QStandardItem* child, const QPoint& pt) { - QList & rlist = gpx_.getRoutes(); - for (int i=0; isetCheckState(i==menuIndex_? Qt::Checked: Qt::Unchecked); - } - rteItem_->setCheckState(Qt::Checked); - mapWidget_->showRoutes(gpx_.getRoutes()); - + QStandardItem* parent = child->parent(); + int row = child->row(); + QMenu menu(this); + menu.addAction(text, this, [this, &row, &parent]()->void { + showOnlyThis(parent, row); + }); + menu.exec(ui_.treeView->mapToGlobal(pt)); } //------------------------------------------------------------------------ void GMapDialog::showContextMenu(const QPoint& pt) { + if constexpr(debug_) { + qDebug() << "showContextMenu"; + } QModelIndex idx = ui_.treeView->indexAt(pt); - QStandardItem* it = model_->itemFromIndex(idx); - int j; - if (model_->indexFromItem(wptItem_) == idx) { - QMenu menu(this); - menu.addAction(tr("Show All Waypoints"), this, &GMapDialog::showAllWaypoints); - menu.addAction(tr("Hide All Waypoints"), this, &GMapDialog::hideAllWaypoints); - menu.addAction(tr("Expand All"), this, &GMapDialog::expandAllWaypoints); - menu.addAction(tr("Collapse All"), this, &GMapDialog::collapseAllWaypoints); - menu.exec(ui_.treeView->mapToGlobal(pt)); - } else if (model_->indexFromItem(rteItem_) == idx) { - QMenu menu(this); - menu.addAction(tr("Show All Routes"), this, &GMapDialog::showAllRoutes); - menu.addAction(tr("Hide All Routes"), this, &GMapDialog::hideAllRoutes); - menu.addAction(tr("Expand All"), this, &GMapDialog::expandAllRoutes); - menu.addAction(tr("Collapse All"), this, &GMapDialog::collapseAllRoutes); - menu.exec(ui_.treeView->mapToGlobal(pt)); - } else if (model_->indexFromItem(trkItem_) == idx) { - QMenu menu(this); - menu.addAction(tr("Show All Tracks"), this, &GMapDialog::showAllTracks); - menu.addAction(tr("Hide All Tracks"), this, &GMapDialog::hideAllTracks); - menu.addAction(tr("Expand All"), this, &GMapDialog::expandAllTracks); - menu.addAction(tr("Collapse All"), this, &GMapDialog::collapseAllTracks); - menu.exec(ui_.treeView->mapToGlobal(pt)); - } else if ((j = waypointIndex(it)) >=0) { - QMenu menu(this); - menu.addAction(tr("Show Only This Waypoint"), this, &GMapDialog::showOnlyThisWaypoint); - menuIndex_ = j; - menu.exec(ui_.treeView->mapToGlobal(pt)); - } else if ((j = trackIndex(it)) >=0) { - QMenu menu(this); - menu.addAction(tr("Show Only This Track"), this, &GMapDialog::showOnlyThisTrack); - menuIndex_ = j; - menu.exec(ui_.treeView->mapToGlobal(pt)); - } else if ((j = routeIndex(it)) >=0) { - QMenu menu(this); - menu.addAction(tr("Show Only This Route"), this, &GMapDialog::showOnlyThisRoute); - menuIndex_ = j; - menu.exec(ui_.treeView->mapToGlobal(pt)); - } else { + if (idx.isValid()) { + QStandardItem* it = model_->itemFromIndex(idx); + if (it == wptItem_) { + const QStringList labels = {tr("Show All Waypoints"), + tr("Hide All Waypoints"), + tr("Expand All"), + tr("Collapse All") + }; + showTopContextMenu(labels, it, pt); + } else if (it == rteItem_) { + const QStringList labels = {tr("Show All Routes"), + tr("Hide All Routes"), + tr("Expand All"), + tr("Collapse All") + }; + showTopContextMenu(labels, it, pt); + } else if (it == trkItem_) { + const QStringList labels = {tr("Show All Tracks"), + tr("Hide All Tracks"), + tr("Expand All"), + tr("Collapse All") + }; + showTopContextMenu(labels, it, pt); + } else if (it != nullptr) { + QStandardItem* parent = it->parent(); + if (parent == wptItem_) { + showChildContextMenu(tr("Show Only This Waypoint"), it, pt); + } else if (parent == trkItem_) { + showChildContextMenu(tr("Show Only This Track"), it, pt); + } else if (parent == rteItem_) { + showChildContextMenu(tr("Show Only This Route"), it, pt); + } + } } } diff --git a/gui/gmapdlg.h b/gui/gmapdlg.h index 43a49d89e..e4dbd1822 100644 --- a/gui/gmapdlg.h +++ b/gui/gmapdlg.h @@ -25,7 +25,6 @@ #include // for QDialog #include // for QItemSelection -#include // for QList #include // for QModelIndex #include // for Q_OBJECT, slots #include // for QPlainTextEdit @@ -42,60 +41,40 @@ class GMapDialog: public QDialog { Q_OBJECT public: - GMapDialog(QWidget* parent, const QString& gpxFileName, QPlainTextEdit* te); + GMapDialog(QWidget* parent, const Gpx& mapData, QPlainTextEdit* te); private: + static constexpr bool debug_ = false; + Ui_GMapDlg ui_; Map* mapWidget_; QStandardItemModel* model_; - QStandardItem* wptItem_, *trkItem_, *rteItem_; - QList wptList_, trkList_, rteList_; - Gpx gpx_; - int menuIndex_; + QStandardItem* wptItem_; + QStandardItem* trkItem_; + QStandardItem* rteItem_; + const Gpx& gpx_; + + static void appendWaypointInfo(QStandardItem* it, const GpxWaypoint& wpt); + static void appendTrackInfo(QStandardItem* it, const GpxTrack& trk); + static void appendRouteInfo(QStandardItem* it, const GpxRoute& rte); - void appendWaypointInfo(QStandardItem* it, const GpxWaypoint& wpt); - void appendTrackInfo(QStandardItem* it, const GpxTrack& trk); - void appendRouteInfo(QStandardItem* it, const GpxRoute& rte); + static QString formatLength(double l); - int waypointIndex(QStandardItem* it); - int trackIndex(QStandardItem* it); - int routeIndex(QStandardItem* it); - QString formatLength(double l); + static void trace(const QString& label, const QStandardItem* it); + void expandCollapseAll(QStandardItem* top, bool exp); + void showHideAll(QStandardItem* top, bool ck); + void showHideChild(const QStandardItem* child); + void showHideChildren(const QStandardItem* top); + void itemClickedX(const QStandardItem* it); + void showOnlyThis(QStandardItem* top, int menuRow); + void showTopContextMenu(const QStringList& text, QStandardItem* top, const QPoint& pt); + void showChildContextMenu(const QString& text, const QStandardItem* child, const QPoint& pt); // private slots: - void itemChangedX(QStandardItem*); - void waypointClickedX(int i); - void trackClickedX(int i); - void routeClickedX(int i); + void itemChangedX(QStandardItem* it); void treeDoubleClicked(const QModelIndex& idx); - void selectionChangedX(const QItemSelection&, const QItemSelection&); - void showContextMenu(const QPoint&); - - - void expandCollapseAll(const QList& li, - QStandardItem* it, bool exp); - void checkUncheckAll(const QList& li, - QStandardItem* it, bool exp); - void expandAllWaypoints(); - void expandAllTracks(); - void expandAllRoutes(); - - void collapseAllWaypoints(); - void collapseAllTracks(); - void collapseAllRoutes(); - - void hideAllWaypoints(); - void hideAllTracks(); - void hideAllRoutes(); - - void showAllWaypoints(); - void showAllTracks(); - void showAllRoutes(); - - void showOnlyThisWaypoint(); - void showOnlyThisTrack(); - void showOnlyThisRoute(); + void selectionChangedX(const QItemSelection& sel, const QItemSelection& desel); + void showContextMenu(const QPoint& pt); }; - #endif diff --git a/gui/gpx.cc b/gui/gpx.cc index ba2ce2c08..f725f253c 100644 --- a/gui/gpx.cc +++ b/gui/gpx.cc @@ -47,30 +47,7 @@ static bool trackIsEmpty(const GpxTrack& trk) class GpxHandler { public: - GpxHandler() - - { - state = e_noop; - } - - enum elementState {e_noop, e_wpt, e_trk, - e_trkpt, e_trkseg, e_rte, e_rtept - }; - QString textChars; - GpxWaypoint currentWpt; - QList wptList; - - QList trkList; - GpxTrack currentTrk; - GpxTrackPoint currentTrkPt; - GpxTrackSegment currentTrkSeg; - - QList rteList; - GpxRoute currentRte; - GpxRoutePoint currentRtePt; - - elementState state; - QList stateStack; + /* Member Functions */ void startElement(QStringView localName, const QXmlStreamAttributes& atts) @@ -204,22 +181,50 @@ public: { textChars = x; } + + /* Data Members */ + + QList wptList; + QList trkList; + QList rteList; + +private: + /* Types */ + + enum elementState {e_noop, e_wpt, e_trk, + e_trkpt, e_trkseg, e_rte, e_rtept + }; + + /* Data Memebers */ + + QString textChars; + GpxWaypoint currentWpt; + + GpxTrack currentTrk; + GpxTrackPoint currentTrkPt; + GpxTrackSegment currentTrkSeg; + + GpxRoute currentRte; + GpxRoutePoint currentRtePt; + + elementState state{e_noop}; + QList stateStack; }; //------------------------------------------------------------------------ -bool Gpx::read(const QString& fileName) +QString Gpx::read(const QString& fileName) { QFile file(fileName); if (!file.open(QIODevice::ReadOnly)) { - return false; + return QStringLiteral("Error opening file %1").arg(fileName); } QXmlStreamReader reader(&file); GpxHandler gpxHandler; - for (bool atEnd = false; !reader.atEnd() && !atEnd;) { + for (bool atEnd = false; !reader.atEnd() && !atEnd;) { reader.readNext(); // do processing switch (reader.tokenType()) { @@ -249,8 +254,8 @@ bool Gpx::read(const QString& fileName) wayPoints = gpxHandler.wptList; tracks = gpxHandler.trkList; routes = gpxHandler.rteList; - return true; + return {}; } - return false; + return QStringLiteral("Error parsing map file: %1").arg(reader.errorString()); } diff --git a/gui/gpx.h b/gui/gpx.h index 473cf178b..da6a33412 100644 --- a/gui/gpx.h +++ b/gui/gpx.h @@ -26,39 +26,13 @@ #include // for QDateTime #include // for QList #include // for QString -#include // for QForeachContainer, qMakeForeachContainer, foreach #include "latlng.h" // for LatLng //------------------------------------------------------------------------ -class GpxItem +class GpxRoutePoint { public: - GpxItem(): visible(true) {} - GpxItem(bool visible): visible(visible) {} - - void setVisible(bool b) - { - visible = b; - } - - bool getVisible() const - { - return visible; - } - -protected: - bool visible; -}; - -//------------------------------------------------------------------------ -class GpxRoutePoint: public GpxItem -{ -public: - GpxRoutePoint(): location(LatLng()), name(QString()) - { - } - void setLocation(const LatLng& pt) { location = pt; @@ -85,32 +59,9 @@ private: }; //------------------------------------------------------------------------ -class GpxRoute: public GpxItem +class GpxRoute { public: - GpxRoute(): name(QString()), cachedLength(-1) {} - - GpxRoute(const GpxRoute& c) - :GpxItem(c.visible), - name(c.name), cachedLength(c.cachedLength) - { - routePoints.clear(); - foreach (GpxRoutePoint sg, c.routePoints) { - routePoints << sg; - } - } - GpxRoute& operator = (const GpxRoute& c) - { - visible = c.visible; - name = c.name; - cachedLength = c.cachedLength; - routePoints.clear(); - foreach (GpxRoutePoint sg, c.routePoints) { - routePoints << sg; - } - return *this; - } - double length() const { if (cachedLength >=0.0) { @@ -119,7 +70,7 @@ public: LatLng prevPt; bool first = true; double dist = 0.0; - foreach (GpxRoutePoint pt, routePoints) { + for (const GpxRoutePoint& pt : routePoints) { if (first) { prevPt = pt.getLocation(); first = false; @@ -160,17 +111,13 @@ public: private: QString name; QList routePoints; - double cachedLength; + double cachedLength{-1.0}; }; //------------------------------------------------------------------------ -class GpxTrackPoint: public GpxItem +class GpxTrackPoint { public: - GpxTrackPoint(): location(LatLng()), elevation(0), dateTime(QDateTime()) - { - } - void setLocation(const LatLng& pt) { location = pt; @@ -203,32 +150,14 @@ public: private: LatLng location; - double elevation; + double elevation{0.0}; QDateTime dateTime; }; //------------------------------------------------------------------------ -class GpxTrackSegment: public GpxItem +class GpxTrackSegment { public: - GpxTrackSegment() {} - - GpxTrackSegment(const GpxTrackSegment& c): GpxItem(c.visible) - { - trackPoints.clear(); - foreach (GpxTrackPoint pt, c.trackPoints) { - trackPoints << pt; - } - } - GpxTrackSegment& operator = (const GpxTrackSegment& c) - { - visible = c.visible; - trackPoints.clear(); - foreach (GpxTrackPoint pt, c.trackPoints) { - trackPoints << pt; - } - return *this; - } void addPoint(const GpxTrackPoint& pt) { trackPoints << pt; @@ -247,39 +176,9 @@ private: QList trackPoints; }; //------------------------------------------------------------------------ -class GpxTrack: public GpxItem +class GpxTrack { public: - GpxTrack(): number(1), name(QString()), comment(QString()), description(QString()), cachedLength(-1.0) {} - - GpxTrack(const GpxTrack& c) - :GpxItem(c.visible), - number(c.number), - name(c.name), - comment(c.comment), - description(c.description), - cachedLength(c.cachedLength) - { - trackSegments.clear(); - foreach (GpxTrackSegment sg, c.trackSegments) { - trackSegments << sg; - } - } - GpxTrack& operator = (const GpxTrack& c) - { - visible = c.visible; - number = c.number; - name = c.name; - comment = c.comment; - description = c.description; - cachedLength = c.cachedLength; - trackSegments.clear(); - foreach (GpxTrackSegment sg, c.trackSegments) { - trackSegments << sg; - } - return *this; - } - void setNumber(int n) { number = n; @@ -342,8 +241,8 @@ public: LatLng prevPt; bool first = true; double dist = 0.0; - foreach (GpxTrackSegment seg, trackSegments) { - foreach (GpxTrackPoint pt, seg.getTrackPoints()) { + for (const GpxTrackSegment& seg : trackSegments) { + for (const GpxTrackPoint& pt : seg.getTrackPoints()) { if (first) { prevPt = pt.getLocation(); first = false; @@ -359,27 +258,18 @@ public: } private: - int number; + int number{1}; QString name; QString comment; QString description; QList trackSegments; - double cachedLength; + double cachedLength{-1.0}; }; //------------------------------------------------------------------------ -class GpxWaypoint: public GpxItem +class GpxWaypoint { public: - GpxWaypoint(): - location_(LatLng(0, 0)), - elevation_(-1.0E-100), - name_(QString()), - comment_(QString()), - description_(QString()), - symbol_(QString()) - {} - void setLocation(const LatLng& pt) { location_ = pt; @@ -442,7 +332,7 @@ public: private: LatLng location_; - double elevation_; + double elevation_{-1.0E-100}; QString name_; QString comment_; QString description_; @@ -453,44 +343,26 @@ private: class Gpx { public: - Gpx() {} - bool read(const QString& fileName); + QString read(const QString& fileName); - QList & getWaypoints() + const QList& getWaypoints() const { return wayPoints; - } // nonconst - - QList & getTracks() - { - return tracks; } - QList & getRoutes() - { - return routes; - } - - const QList & getWaypoints() const - { - return wayPoints; - } - - const QList & getTracks() const + const QList& getTracks() const { return tracks; } - const QList & getRoutes() const + const QList& getRoutes() const { return routes; } private: QList wayPoints; - QList tracks; - QList routes; + QList tracks; + QList routes; }; - - #endif diff --git a/gui/latlng.h b/gui/latlng.h index 44c390108..bfff8718c 100644 --- a/gui/latlng.h +++ b/gui/latlng.h @@ -28,7 +28,7 @@ class LatLng { public: - LatLng(): _lat(0), _lng(0) {} + LatLng() = default; LatLng(double lat, double lng): _lat(lat), _lng(lng) {} double lat() const { @@ -41,8 +41,8 @@ public: double haversineDistance(const LatLng& other) const; private: - double _lat; - double _lng; + double _lat{0.0}; + double _lng{0.0}; }; diff --git a/gui/mainwindow.cc b/gui/mainwindow.cc index 643ca9bcb..0f10d5c77 100644 --- a/gui/mainwindow.cc +++ b/gui/mainwindow.cc @@ -66,6 +66,7 @@ #include "formatload.h" // for FormatLoad #include "gbversion.h" // for VERSION, kVersionDate, kVersionSHA #ifndef DISABLE_MAPPREVIEW +#include "gpx.h" // for Gpx #include "gmapdlg.h" // for GMapDialog #endif #include "help.h" // for ShowHelp @@ -968,12 +969,25 @@ void MainWindow::applyActionX() ui_.outputWindow->appendPlainText(tr("Translation successful")); #ifndef DISABLE_MAPPREVIEW if (babelData_.previewGmap_) { - this->hide(); - GMapDialog dlg(nullptr, tempName, babelData_.debugLevel_ >=1 ? ui_.outputWindow : nullptr); - dlg.show(); - dlg.exec(); + Gpx mapData; + QString mapStatus = mapData.read(tempName); QFile(tempName).remove(); - this->show(); + if (!mapStatus.isNull()) { + QTextCharFormat defaultFormat = ui_.outputWindow->currentCharFormat(); + QTextCharFormat errorFormat = defaultFormat; + errorFormat.setForeground(Qt::red); + errorFormat.setFontItalic(true); + + ui_.outputWindow->setCurrentCharFormat(errorFormat); + ui_.outputWindow->appendPlainText(tr("Error preparing map: %1\n").arg(mapStatus)); + ui_.outputWindow->setCurrentCharFormat(defaultFormat); + } else { + this->hide(); + GMapDialog dlg(nullptr, mapData, babelData_.debugLevel_ >=1 ? ui_.outputWindow : nullptr); + dlg.show(); + dlg.exec(); + this->show(); + } } #endif } else { diff --git a/gui/map.cc b/gui/map.cc index 547a3f571..b70792194 100644 --- a/gui/map.cc +++ b/gui/map.cc @@ -28,6 +28,7 @@ #include // for QFile #include // for QIODevice #include // for QLatin1String +#include // for QList #include // for QMessageBox #include // for QNetworkAccessManager #include // for qMakeStringPrivate, QStringLiteral @@ -37,7 +38,6 @@ #include // for QWebEngineSettings #include // for QWebEngineView #include // for CursorShape -#include // for QForeachContainer, qMakeForeachContainer, foreach #include // for string #include // for vector @@ -53,22 +53,15 @@ using std::vector; //------------------------------------------------------------------------ static QString stripDoubleQuotes(const QString& s) { - QString out; - foreach (QChar c, s) { - if (c != QChar('"')) { - out += c; - } - } - return out; + QString out = s; + return out.remove('"'); } //------------------------------------------------------------------------ Map::Map(QWidget* parent, - const Gpx& gpx, QPlainTextEdit* te): + const Gpx& gpx, QPlainTextEdit* te): QWebEngineView(parent), gpx_(gpx), - mapPresent_(false), - busyCursor_(false), textEdit_(te) { busyCursor_ = true; @@ -90,7 +83,7 @@ Map::Map(QWidget* parent, // 1. In the file system in the same directory as the executable. // 2. In the Qt resource system. This is useful if the resource was compiled // into the executable. - QString baseFile = QApplication::applicationDirPath() + "/gmapbase.html"; + QString baseFile = QApplication::applicationDirPath() + "/gmapbase.html"; QString fileName; QUrl baseUrl; if (QFile(baseFile).exists()) { @@ -193,7 +186,7 @@ void Map::loadFinishedX(bool f) //------------------------------------------------------------------------ static QString fmtLatLng(const LatLng& l) { - return QString("{lat: %1, lng: %3}").arg(l.lat(), 0, 'f', 5) .arg(l.lng(), 0, 'f', 5); + return QString("{lat: %1, lng: %3}").arg(l.lat(), 0, 'f', 5) .arg(l.lng(), 0, 'f', 5); } //------------------------------------------------------------------------ @@ -239,7 +232,7 @@ void Map::showGpxData() // Waypoints. int num=0; - foreach (const GpxWaypoint& pt, gpx_.getWaypoints()) { + for (const GpxWaypoint& pt : gpx_.getWaypoints()) { scriptStr << QString("waypts[%1] = new google.maps.Marker({map: map, position: %2, " "title: \"%3\", icon: blueIcon});") @@ -258,10 +251,10 @@ void Map::showGpxData() // Tracks num = 0; - foreach (const GpxTrack& trk, gpx_.getTracks()) { + for (const GpxTrack& trk : gpx_.getTracks()) { vector pts; - foreach (const GpxTrackSegment seg, trk.getTrackSegments()) { - foreach (const GpxTrackPoint pt, seg.getTrackPoints()) { + for (const GpxTrackSegment& seg : trk.getTrackSegments()) { + for (const GpxTrackPoint& pt : seg.getTrackPoints()) { pts.push_back(pt.getLocation()); } } @@ -287,9 +280,9 @@ void Map::showGpxData() // Routes num = 0; - foreach (const GpxRoute& rte, gpx_.getRoutes()) { + for (const GpxRoute& rte : gpx_.getRoutes()) { vector pts; - foreach (const GpxRoutePoint& pt, rte.getRoutePoints()) { + for (const GpxRoutePoint& pt : rte.getRoutePoints()) { pts.push_back(pt.getLocation()); } QString path = makePath(pts); @@ -333,7 +326,6 @@ void Map::markerClicked(int t, int i) } else if (t == 2) { emit routeClicked(i); } - } //------------------------------------------------------------------------ @@ -346,75 +338,6 @@ void Map::logTime(const QString& s) stopWatch_.start(); } //------------------------------------------------------------------------ -void Map::showTracks(const QList& tracks) -{ - QStringList scriptStr; - int i=0; - foreach (const GpxTrack& trk, tracks) { - scriptStr << QString("trks[%1].%2();").arg(i).arg(trk.getVisible()?"show":"hide"); - i++; - } - evaluateJS(scriptStr); -} - -//------------------------------------------------------------------------ -void Map::hideAllTracks() -{ - QStringList scriptStr; - scriptStr - << "for (idx = 0; idx < trks.length; idx += 1) {" - << " trks[idx].hide();" - << "}" - ; - evaluateJS(scriptStr); -} - -//------------------------------------------------------------------------ -// TACKY: we assume the waypoints list and JS waypts[] are parallel. -void Map::showWaypoints(const QList& waypoints) -{ - QStringList scriptStr; - int i=0; - foreach (const GpxWaypoint& pt, waypoints) { - scriptStr << QString("waypts[%1].setVisible(%2);").arg(i++).arg(pt.getVisible()?"true":"false"); - } - evaluateJS(scriptStr); -} -//------------------------------------------------------------------------ -void Map::hideAllWaypoints() -{ - QStringList scriptStr; - scriptStr - << "for (idx = 0; idx < waypts.length; idx += 1) {" - << " waypts[idx].setVisible(false);" - << "}" - ; - evaluateJS(scriptStr); -} - -//------------------------------------------------------------------------ -void Map::showRoutes(const QList& routes) -{ - QStringList scriptStr; - int i=0; - foreach (const GpxRoute& rt, routes) { - scriptStr << QString("rtes[%1].%2();").arg(i).arg(rt.getVisible()?"show":"hide"); - i++; - } - evaluateJS(scriptStr); -} -//------------------------------------------------------------------------ -void Map::hideAllRoutes() -{ - QStringList scriptStr; - scriptStr - << "for (idx = 0; idx < rtes.length; idx += 1) {" - << " rtes[idx].hide();" - << "}" - ; - evaluateJS(scriptStr); -} -//------------------------------------------------------------------------ void Map::setWaypointVisibility(int i, bool show) { evaluateJS(QString("waypts[%1].setVisible(%2);") @@ -433,6 +356,15 @@ void Map::setRouteVisibility(int i, bool show) evaluateJS(QString("rtes[%1].%2();").arg(i).arg(show?"show": "hide")); } +//------------------------------------------------------------------------ +void Map::resetBounds() +{ + evaluateJS(QStringList{ + "map.setCenter(bounds.getCenter());", + "map.fitBounds(bounds);", + }); +} + //------------------------------------------------------------------------ void Map::panTo(const LatLng& loc) { @@ -463,29 +395,21 @@ void Map::setWaypointColorBlue(int i) //------------------------------------------------------------------------ void Map::frameTrack(int i) { - QStringList scriptStr; - - scriptStr - << QString("map.setCenter(trks[%1].getBounds().getCenter());").arg(i) - << QString("map.fitBounds(trks[%1].getBounds());").arg(i) - - ; - evaluateJS(scriptStr); + evaluateJS(QStringList{ + QString("map.setCenter(trks[%1].getBounds().getCenter());").arg(i), + QString("map.fitBounds(trks[%1].getBounds());").arg(i), + }); } - //------------------------------------------------------------------------ void Map::frameRoute(int i) { - QStringList scriptStr; - scriptStr - << QString("map.setCenter(rtes[%1].getBounds().getCenter());").arg(i) - << QString("map.fitBounds(rtes[%1].getBounds());").arg(i) - ; - evaluateJS(scriptStr); + evaluateJS(QStringList{ + QString("map.setCenter(rtes[%1].getBounds().getCenter());").arg(i), + QString("map.fitBounds(rtes[%1].getBounds());").arg(i), + }); } - //------------------------------------------------------------------------ void Map::evaluateJS(const QString& s, bool upd) { diff --git a/gui/map.h b/gui/map.h index bf1d7b19f..26aa9a7f8 100644 --- a/gui/map.h +++ b/gui/map.h @@ -25,7 +25,6 @@ #include // for QByteArray #include // for QElapsedTimer -#include // for QList #include // for QNetworkAccessManager #include // for QObject, emit, Q_OBJECT, signals, slots #include // for QPlainTextEdit @@ -70,43 +69,33 @@ signals: }; - class Map : public QWebEngineView { Q_OBJECT public: Map(QWidget* parent, - const Gpx& gpx_, QPlainTextEdit* textEdit_); + const Gpx& gpx_, QPlainTextEdit* textEdit_); ~Map(); -public slots: void showGpxData(); - - void showTracks(const QList& tracks); - void hideAllTracks(); void setTrackVisibility(int i, bool show); - - void showWaypoints(const QList& waypoints); - void hideAllWaypoints(); void setWaypointVisibility(int i, bool show); - - void showRoutes(const QList& routes); - void hideAllRoutes(); void setRouteVisibility(int i, bool show); - - void loadFinishedX(bool); - void markerClicked(int t, int i); + void resetBounds(); void panTo(const LatLng& loc); void setWaypointColorRed(int i); void setWaypointColorBlue(int i); void frameTrack(int i); void frameRoute(int i); - void logTime(const QString&); +public slots: + void loadFinishedX(bool f); + void markerClicked(int t, int i); + void logTime(const QString& s); private: - QByteArray encodeKey(const QByteArray& key); - QByteArray decodeKey(const QByteArray& key); + static QByteArray encodeKey(const QByteArray& key); + static QByteArray decodeKey(const QByteArray& key); signals: void waypointClicked(int i); @@ -115,24 +104,20 @@ signals: private: #ifdef DEBUG_JS_GENERATION - QFile* dbgdata_; - QTextStream* dbgout_; + QFile* dbgdata_{nullptr}; + QTextStream* dbgout_{nullptr}; #endif - QNetworkAccessManager* manager_; + QNetworkAccessManager* manager_{nullptr}; const Gpx& gpx_; - bool mapPresent_; - bool busyCursor_; + bool mapPresent_{false}; + bool busyCursor_{false}; QElapsedTimer stopWatch_; - QPlainTextEdit* textEdit_; + QPlainTextEdit* textEdit_{nullptr}; void evaluateJS(const QString& s, bool update = true); void evaluateJS(const QStringList& s, bool update = true); - protected: void resizeEvent(QResizeEvent* event) override; - }; - - #endif // HEADER_H